package com.partsoft.loader.context;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.partsoft.loader.log.Log;
import com.partsoft.utils.ClassUtils;
import com.partsoft.utils.ListUtils;

public class ContextServiceManager implements ContextServiceAdapter {

	private Object manualService;

	private Map<Class<?>, Map<LifeCycleOperation, Method>> clazzLifeCycleMethodMap = new HashMap<Class<?>, Map<LifeCycleOperation, Method>>();
	
	private Set<Object> startedService = new LinkedHashSet<Object>();

	public void setServices(List<Object> manualService) {
		this.manualService = manualService;
	}

	public void addService(Object manualService) {
		this.manualService = ListUtils.add(this.manualService, manualService);
	}

	public boolean removeService(Object manualService) {
		return this.manualService != null ? ListUtils.remove(this.manualService, manualService) != null : false;
	}

	public void setLifeCycleClassMethods(Map<Class<?>, Map<String, String>> maps) {
		clazzLifeCycleMethodMap = new HashMap<Class<?>, Map<LifeCycleOperation, Method>>();
		for (Map.Entry<Class<?>, Map<String, String>> mapEntry : maps.entrySet()) {
			Class<?> clazz = mapEntry.getKey();
			Map<LifeCycleOperation, Method> methodMapValue = new HashMap<LifeCycleOperation, Method>(2);
			for (Map.Entry<String, String> methodEntry : mapEntry.getValue().entrySet()) {
				String lifeCycleName = methodEntry.getKey();
				LifeCycleOperation op = LifeCycleOperation.fromName(lifeCycleName);
				if (op == null) {
					throw new IllegalStateException(String.format("无法找到服务类(%s)的操作类型(%s)", clazz.getName(), lifeCycleName));
				}
				String methodName = methodEntry.getValue();
				Method method = ClassUtils.getMethodIfAvailable(clazz, methodName, new Class[0]);
				if (method == null) {
					throw new IllegalStateException(String.format("无法找服务类(%s)的方法(%s)", clazz.getName(), methodName));
				}
				methodMapValue.put(op, method);
			}
			if (!methodMapValue.containsKey(LifeCycleOperation.START)) {
				throw new IllegalStateException(String.format("服务类(%s)的没有找到启动模式", clazz.getName()));
			}
			clazzLifeCycleMethodMap.put(clazz, methodMapValue);
		}
	}

	public void start() throws Exception {
		int svcCount = ListUtils.size(this.manualService);
		for (int i = 0; i < svcCount; i++) {
			Object svcObject = ListUtils.get(this.manualService, i);
			if (svcObject == null) {
				throw new IllegalStateException("服务对象不能为空");
			}
			Class<?> opClazz = null;
			Method opMethod = null;
			for (Map.Entry<Class<?>, Map<LifeCycleOperation, Method>> opMethodEntry : this.clazzLifeCycleMethodMap.entrySet()) {
				Class<?> tmpClazz = opMethodEntry.getKey();
				if (ClassUtils.isAssignableValue(tmpClazz, svcObject)) {
					opClazz = tmpClazz;
					opMethod = opMethodEntry.getValue().get(LifeCycleOperation.START);
					break;
				}
			}

			if (opClazz == null) {
				throw new IllegalStateException(String.format("服务对象(类%s)找不到服务操作方法定义", svcObject.getClass().getName()));
			}

			if (opMethod == null) {
				continue;
			}
			boolean oldAccess = opMethod.isAccessible();
			try {
				opMethod.setAccessible(true);
				opMethod.invoke(svcObject);
				
				startedService.add(svcObject);
				
			} catch (InvocationTargetException e) {
				throw new IllegalStateException(e.getTargetException().getMessage(), e.getTargetException());
			} catch (Throwable e) {
				throw new IllegalStateException(e);
			} finally {
				opMethod.setAccessible(oldAccess);
			}
		}
	}

	public void stop() {
		int svcCount = ListUtils.size(this.manualService);
		for (int i = svcCount - 1; i >= 0; i--) {
			Object svcObject = ListUtils.get(this.manualService, i);
			if (!startedService.contains(svcObject)) {
				continue;
			}
			startedService.remove(svcObject);
			if (svcObject == null) {
				throw new IllegalStateException("服务对象不能为空");
			}
			Class<?> opClazz = null;
			Method opMethod = null;
			for (Map.Entry<Class<?>, Map<LifeCycleOperation, Method>> opMethodEntry : this.clazzLifeCycleMethodMap.entrySet()) {
				Class<?> tmpClazz = opMethodEntry.getKey();
				if (ClassUtils.isAssignableValue(tmpClazz, svcObject)) {
					opClazz = tmpClazz;
					opMethod = opMethodEntry.getValue().get(LifeCycleOperation.STOP);
					break;
				}
			}

			if (opClazz == null) {
				throw new IllegalStateException(String.format("服务对象(类%s)找不到服务操作方法定义", svcObject.getClass().getName()));
			}

			if (opMethod == null)
				continue;
			boolean oldAccess = opMethod.isAccessible();
			try {
				opMethod.setAccessible(true);
				opMethod.invoke(svcObject);
				try {
					Thread.yield();
					Thread.sleep(500);
					Thread.yield();
				} catch (Throwable e) {
					Log.ignore(e);
				}
			} catch (Throwable e) {
				if (Log.isDebugEnabled()) {
					Log.debug(String.format("停止服务(类%s)时发生错误: %s", opClazz.getName(), e.getMessage()), e);
				}
			} finally {
				opMethod.setAccessible(oldAccess);
			}
		}
	}

}
